package com.lqg.bookLibrary.service.recommend;

import com.lqg.bookLibrary.pojo.Score;
import com.lqg.bookLibrary.service.IScoreService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class RateRecommend<TB, TU> {

    @Autowired
    private IScoreService scoreService;

    // 计算两个用户的相似度（采用余弦相似度计算）
    private double similarity(TU userId1, TU userId2,Map<TU, Map<TB, Integer>> ratingsData) {
        // 得到user1 与 user2 的评分表
        Map<TB, Integer> user1Ratings = ratingsData.get(userId1);
        Map<TB, Integer> user2Ratings = ratingsData.get(userId2);

        double dotProduct = 0.0, norm1 = 0.0, norm2 = 0.0;

        for (Map.Entry<TB, Integer> entry : user1Ratings.entrySet()) {
            TB book = entry.getKey();
            int user1Rating = entry.getValue();
            if (user2Ratings.containsKey(book)) {
                int user2Rating = user2Ratings.get(book);
                dotProduct += user1Rating * user2Rating;
            }
            norm1 += user1Rating * user1Rating;
        }

        for (Map.Entry<TB, Integer> entry : user2Ratings.entrySet()) {
            int user2Rating = entry.getValue();
            norm2 += user2Rating * user2Rating;
        }

        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }

    // 给用户推荐图书
    public List<TB> recommendBooks(TU userId) {

        // 查询数据库
        Map<TU, Map<TB, Integer>> ratingsData = new HashMap<>();
        List<Score> list = scoreService.list();
        //while ()
        for (Score score : list) {
            if (ratingsData.containsKey(score.getUserId())) {
                Map<TB, Integer> tbIntegerMap = ratingsData.get(score.getUserId());
                if (ratingsData.get(score.getUserId()).containsKey(score.getBookId())) {
                    ratingsData.get(score.getUserId()).replace((TB) score.getBookId(), score.getScoreNum());
                }else {
                    ratingsData.get(score.getUserId()).put((TB) score.getBookId(), score.getScoreNum());
                }
            }else{
                HashMap<TB, Integer> map = new HashMap<>();
                map.put((TB) score.getBookId(),score.getScoreNum());
                ratingsData.put((TU) score.getUserId(), map);
            }
        }

        // 候选集
        Map<TB, Double> candidateItems = new HashMap<>();
        // 去除当前用户
        Set<TU> otherUsers = new HashSet<>(ratingsData.keySet());
        otherUsers.remove(userId);

        // 遍历其他用户
        for (TU otherUser : otherUsers) {
            double similarityScore = similarity(userId, otherUser, ratingsData);
            // 如果相似度为0，则跳过
            if (similarityScore <= 0.0) {
                continue;
            }

            Map<TB, Integer> otherUserRatings = ratingsData.get(otherUser);

            for (Map.Entry<TB, Integer> entry : otherUserRatings.entrySet()) {
                TB book = entry.getKey();
                int rating = entry.getValue();

                if (!ratingsData.get(userId).containsKey(book)) {
                    candidateItems.put(book,
                            candidateItems.getOrDefault(book, 0.0) + rating * similarityScore);
                }
            }
        }

        // 按推荐度排序
        List<TB> sortedBooks = new ArrayList<>(candidateItems.keySet());
        sortedBooks.sort((book1, book2) -> candidateItems.get(book2).compareTo(candidateItems.get(book1)));

        return sortedBooks;
    }

}
